package com.chigga.application.exception;

import com.chigga.common.constants.HttpStatusConstant;
import com.chigga.common.core.domain.ResponseResult;
import com.chigga.common.exception.InstanceAlreadyExistsException;
import com.chigga.common.exception.InstanceNotExistsException;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.HandlerMethodValidationException;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.resource.NoResourceFoundException;

import java.sql.SQLException;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 全局异常处理器
 * 用于捕获和处理应用程序中抛出的各种异常，并返回统一的错误响应。
 * @author DefChigga
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 处理全局异常（Exception.class）。
     * 捕获所有未被其他异常处理器处理的异常。
     *
     * @param ex 捕获到的异常
     * @return 返回一个包含错误信息的ResponseResult对象，状态码为INTERNAL_SERVER_ERROR
     */
    @ExceptionHandler(Exception.class)
    public ResponseResult<String> handleGlobalException(Exception ex) {
        log.error("全局异常处理器: ", ex);
        return ResponseResult.failure(HttpStatusConstant.INTERNAL_SERVER_ERROR, "服务器内部错误，请稍后再试");
    }

    /**
     * 处理空指针异常（NullPointerException）。
     * 捕获应用程序中可能出现的空指针异常。
     *
     * @param ex 捕获到的空指针异常
     * @return 返回一个包含错误信息的ResponseResult对象，状态码为INTERNAL_SERVER_ERROR
     */
    @ExceptionHandler(NullPointerException.class)
    public ResponseResult<String> handleNullPointerException(NullPointerException ex) {
        log.error("空指针异常: ", ex);
        return ResponseResult.failure(HttpStatusConstant.INTERNAL_SERVER_ERROR, "操作失败，可能存在空值引用");
    }

    /**
     * 处理非法参数异常（IllegalArgumentException）。
     * 捕获应用程序中可能出现的非法参数异常。
     *
     * @param ex 捕获到的非法参数异常
     * @return 返回一个包含错误信息的ResponseResult对象，状态码为BAD_REQUEST
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseResult<String> handleIllegalArgumentException(IllegalArgumentException ex) {
        log.error("非法参数异常: ", ex);
        return ResponseResult.failure(HttpStatusConstant.BAD_REQUEST, "请求参数不合法: " + ex.getMessage());
    }

    /**
     * 处理资源未找到异常（NoHandlerFoundException）。
     * 捕获请求资源未找到的异常。
     *
     * @param ex 捕获到的资源未找到异常
     * @return 返回一个包含错误信息的ResponseResult对象，状态码为NOT_FOUND
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    public ResponseResult<String> handleNoHandlerFoundException(NoHandlerFoundException ex) {
        log.error("资源未找到异常: ", ex);
        return ResponseResult.failure(HttpStatusConstant.NOT_FOUND, "资源未找到: " + ex.getRequestURL());
    }

    /**
     * 处理数据访问异常（DataAccessException）。
     * 捕获数据库操作过程中可能出现的异常。
     *
     * @param ex 捕获到的数据访问异常
     * @return 返回一个包含错误信息的ResponseResult对象，状态码为INTERNAL_SERVER_ERROR
     */
    @ExceptionHandler(DataAccessException.class)
    public ResponseResult<String> handleDataAccessException(DataAccessException ex) {
        log.error("数据访问异常: ", ex);
        return ResponseResult.failure(HttpStatusConstant.INTERNAL_SERVER_ERROR, "数据库操作失败");
    }

    /**
     * 处理HTTP请求方法不支持异常（HttpRequestMethodNotSupportedException）。
     * 捕获请求方法不被支持的异常。
     *
     * @param ex 捕获到的HTTP请求方法不支持异常
     * @return 返回一个包含错误信息的ResponseResult对象，状态码为METHOD_NOT_ALLOWED
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public ResponseResult<String> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex) {
        log.error("HTTP请求方法不支持异常: ", ex);
        return ResponseResult.failure(HttpStatusConstant.METHOD_NOT_ALLOWED, "请求方法不被允许: " + ex.getMethod());
    }

    /**
     * 处理HTTP媒体类型不支持异常（HttpMediaTypeNotSupportedException）。
     * 捕获请求媒体类型不被支持的异常。
     *
     * @param ex 捕获到的HTTP媒体类型不支持异常
     * @return 返回一个包含错误信息的ResponseResult对象，状态码为UNSUPPORTED_TYPE
     */
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public ResponseResult<String> handleHttpMediaTypeNotSupported(HttpMediaTypeNotSupportedException ex) {
        log.error("HTTP媒体类型不支持异常: ", ex);
        return ResponseResult.failure(HttpStatusConstant.UNSUPPORTED_TYPE, "请求媒体类型不支持: " + ex.getContentType());
    }

    /**
     * 处理请求参数缺失异常（MissingServletRequestParameterException）。
     * 捕获请求中缺少必要参数的异常。
     *
     * @param ex 捕获到的请求参数缺失异常
     * @return 返回一个包含错误信息的ResponseResult对象，状态码为BAD_REQUEST
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ResponseResult<String> handleMissingServletRequestParameterException(MissingServletRequestParameterException ex) {
        log.error("请求参数绑定异常: ", ex);
        return ResponseResult.failure(HttpStatusConstant.BAD_REQUEST, "缺少必要的请求参数: " + ex.getParameterName());
    }

    /**
     * 处理方法参数校验异常（MethodArgumentNotValidException）。
     * 捕获方法参数校验失败的异常。
     *
     * @param ex 捕获到的方法参数校验异常
     * @return 返回一个包含错误信息的ResponseResult对象，状态码为BAD_REQUEST
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseResult<String> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        log.error("参数校验异常: ", ex);
        FieldError fieldError = ex.getBindingResult().getFieldError();
        String errorMessage = fieldError != null ? fieldError.getDefaultMessage() : "参数错误";
        return ResponseResult.failure(HttpStatusConstant.BAD_REQUEST, "参数校验失败: " + errorMessage);
    }

    /**
     * 处理请求体缺失或格式错误异常（HttpMessageNotReadableException）。
     * 捕获请求体缺失或格式错误的异常。
     *
     * @param ex 捕获到的请求体缺失或格式错误异常
     * @return 返回一个包含错误信息的ResponseResult对象，状态码为BAD_REQUEST
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public ResponseResult<String> handleHttpMessageNotReadableException(HttpMessageNotReadableException ex) {
        log.error("请求体缺失或格式错误: ", ex);
        return ResponseResult.failure(HttpStatusConstant.BAD_REQUEST, "请求体缺失或格式错误");
    }

    /**
     * 处理文件上传异常（MultipartException）。
     * 捕获文件上传过程中可能出现的异常。
     *
     * @param ex 捕获到的文件上传异常
     * @return 返回一个包含错误信息的ResponseResult对象，状态码为BAD_REQUEST
     */
    @ExceptionHandler(MultipartException.class)
    public ResponseResult<String> handleMultipartException(MultipartException ex) {
        log.error("文件上传异常: ", ex);
        return ResponseResult.failure(HttpStatusConstant.BAD_REQUEST, "文件上传失败");
    }

    /**
     * 处理资源未找到异常（NoResourceFoundException）。
     * 捕获静态资源未找到的异常。
     *
     * @param ex 捕获到的资源未找到异常
     * @return 返回一个包含错误信息的ResponseResult对象，状态码为NOT_FOUND
     */
    @ExceptionHandler(NoResourceFoundException.class)
    public ResponseResult<String> handleNoResourceFoundException(NoResourceFoundException ex) {
        String resourcePath = ex.getResourcePath();
        log.error("资源未找到: {}", resourcePath, ex);
        return ResponseResult.failure(HttpStatusConstant.NOT_FOUND, "资源未找到");
    }

    /**
     * 处理方法参数校验异常（HandlerMethodValidationException）。
     * 捕获方法参数校验失败的异常。
     *
     * @param ex 捕获到的方法参数校验异常
     * @return 返回一个包含错误信息的ResponseResult对象，状态码为BAD_REQUEST
     */
    @ExceptionHandler(HandlerMethodValidationException.class)
    public ResponseResult<String> handleHandlerMethodValidationException(HandlerMethodValidationException ex) {
        log.error("参数校验异常: ", ex);
        return ResponseResult.failure(HttpStatusConstant.BAD_REQUEST, "参数校验失败");
    }

    /**
     * 处理约束校验异常（ConstraintViolationException）。
     * 捕获Bean Validation校验失败的异常。
     *
     * @param ex 捕获到的约束校验异常
     * @return 返回一个包含错误信息的ResponseResult对象，消息为所有校验失败的错误信息拼接而成的字符串
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseResult<?> handleValidationException(ConstraintViolationException ex) {
        log.error("参数校验异常: ", ex);
        String message = ex.getConstraintViolations().stream()
                .map(ConstraintViolation::getMessage)
                .collect(Collectors.joining(", "));
        return ResponseResult.failure(HttpStatusConstant.BAD_REQUEST, message);
    }

    /**
     * 处理方法参数类型不匹配异常（MethodArgumentTypeMismatchException）。
     * @param ex 捕获到的方法参数类型不匹配异常
     * @return 返回一个包含错误信息的ResponseResult对象，状态码为BAD_REQUEST
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public ResponseResult<String> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException ex) {
        log.error("参数类型不匹配异常: ", ex);
        String message = "参数类型不匹配: " + ex.getName() + " 必须是 " + Objects.requireNonNull(ex.getRequiredType()).getSimpleName() + " 类型";
        return ResponseResult.failure(HttpStatusConstant.BAD_REQUEST, message);
    }

    /**
     * 处理实例已存在异常（InstanceAlreadyExistsException）。
     * @param ex 捕获到的实例已存在异常
     * @return 返回一个包含错误信息的ResponseResult对象，状态码为CONFLICT
     */
    @ExceptionHandler(InstanceAlreadyExistsException.class)
    public ResponseResult<String> handleInstanceAlreadyExistsException(InstanceAlreadyExistsException ex) {
        log.error("实例已存在异常: ", ex);
        return ResponseResult.failure(HttpStatusConstant.CONFLICT, ex.getMessage());
    }

    /**
     * 处理实例不存在异常（InstanceNotExistsException）。
     * @param ex 捕获到的实例不存在异常
     * @return 返回一个包含错误信息的ResponseResult对象，状态码为NOT_FOUND
     */
    @ExceptionHandler(InstanceNotExistsException.class)
    public ResponseResult<String> handleInstanceNotExistsException(InstanceNotExistsException ex) {
        log.error("实例不存在异常: ", ex);
        return ResponseResult.failure(HttpStatusConstant.NOT_FOUND, ex.getMessage());
    }

    /**
     * 处理SQL语法错误异常（BadSqlGrammarException）。
     * @param ex 捕获到的SQL语法错误异常
     * @return 返回一个包含错误信息的ResponseResult对象，状态码为BAD_REQUEST
     */
    @ExceptionHandler(BadSqlGrammarException.class)
    public ResponseResult<String> handleBadSqlGrammarException(BadSqlGrammarException ex) {
        log.error("SQL语法错误异常: ", ex);
        // 判断如果是排序字段问题，返回400，否则返回500
        SQLException exception = ex.getSQLException();
        if(exception != null && exception.getMessage() != null) {
            if (ex.getMessage().contains("Unknown column") && ex.getMessage().contains("in 'order clause" )) {
                return ResponseResult.failure(HttpStatusConstant.BAD_REQUEST, "排序字段不存在：" + exception.getMessage());
            }
        }
        return ResponseResult.failure(HttpStatusConstant.INTERNAL_SERVER_ERROR, "SQL语法错误：" + ex.getMessage());
    }
}